//== SAGITTARIUS ============================================================================

//== FILEDOC =========================================================================

/** @file pAST.h
  * @brief Abstract syntax tree for the parser
  */

//== BEGINNING OF CODE ===============================================================

#ifndef __SAGUTTARUIS__PAST__H_
#define __SAGUTTARUIS__PAST__H_

//== INCLUDES ========================================================================

#include "sagittarius/core/SagittariusCore.h"
#include "sagittarius/parser/parserNodes.h"
#include "sagittarius/symtab/symtab.h"
#include "sagittarius/types/types.h"
#include "sagittarius/builtins/builtins.h"

#ifdef __cplusplus
extern "C" {
#endif

typedef struct __parserExp parserExp;

/** @brief Single import
 */
typedef struct __singleImport {
    /// Symbol
    symcode sym;
    /// Symbol expression
    parserExp* sexp;
    /// Expression
    parserExp* exp;
    int subsume;
    /// Symbol
    sg_name_val* m;
} singleImport;

/** @brief Constructor for single import
 */
singleImport* createSingleImport();

/** @brief Destructor for single import
 */
void destroySingleImport(singleImport* p);

/** @brief Dump
 */
void dumpSingleImport(int fd, singleImport* p, uint64 ind, symtab* st);

/** @brief Module/symbol import
 */
typedef struct __importStmt {
    uint64 c;
    uint64 n;
    singleImport** p;
} importStmt;

/** @brief Constructor for import stmt
 */
importStmt* createImportStmt();

/** @brief Destructor for function def
 */
void destroyImportStmt(importStmt* p);

void importStmtPushSingle(importStmt* p, singleImport* s);

/** @brief Dumps info about the source
 */
void dumpImportStmt(int fd, importStmt* p, uint64 ind, symtab* st);

void dumpPAST_type(int fd, parserExpType t, uint64 ind);

typedef struct {
    /// buffer
    constLexBuf w;
    /// length
    uint64 l;
} past_strValue;

typedef struct __parserExp {
    /// Type of the node
    parserExpType type;
    /// Pointer to child nodes
    struct __parserExp* a;
    int owna;
    struct __parserExp* b;
    int ownb;
    
    // Lvalue data
    
    /// Id for lvalue, if this node holds one
    symcode lvalid;
    
    /// Id for feature, if this node holds one
    //symcode feat_id;
    //int have_feat;
    
    // Rvalue data
    
    // integral value
    union {
       uint64 u;
       int64 s;
       importStmt* imp;
       //Real r;
       past_strValue str;
    } v;
    
    /// LH child
    //struct __parserExp* a;
    /// RH child
    //struct __parserExp* b;
    
    /// Line no (negative if unavailable)
    int64 ln;
} parserExp;

/** @brief Constructor for exp nodes
 */
parserExp* createParserExp();

/** @brief Destructor for exp nodes
 */
void destroyParserExp(parserExp* p);

sg_OpPrec sg_getOpPrec(parserExpType);

/** @brief Dump info for @ref paramList to output
 */
void dumpParserExp(int fd, parserExp* e, uint64 ind, symtab* st, sg_OpPrec prec);

/** @brief Get # args
 */
int64 getNumCallExpArgs(parserExp* e);

/** @brief Get the terminal field of a chain of faccesses
 */
symcode getTerminalField(parserExp* e);

/** @brief Get the symcode for a symbol node (fails for non-symbol nodes)
 */
symcode exprGetSymbol(parserExp* e);

/** @brief Body of a function or other code block
 */
typedef struct {
    /// Number of expressions
    uint64 n;
    /// List of expressions
    parserExp** e;
} basicBody;

/** @brief Constructor for param list
 */
basicBody* createBasicBody();

/** @brief Destructor for param nodes
 */
void destroyBasicBody(basicBody* b);

/** @brief Push an expression
 */
void basicBodyPushExp(basicBody* b, parserExp* e);

/** @brief Dump info for @ref basicBody to output
 */
void dumpBasicBody(int fd, basicBody* b, uint64 ind, symtab* st);

typedef struct __paramListElt {
    symid sym;
    /// Is ref?
    int ref;
} paramListElt;

typedef struct {
    size_t n;
    paramListElt* p;
} paramList;

/** @brief Constructor for param list
 */
paramList* createParamList();

/** @brief Destructor for param nodes
 */
void destroyParamList(paramList* l);

/** @brief Push this element onto the list
 */
void paramListPush(paramList* l, paramListElt e);

/** @brief Dump info for @ref paramList to output
 */
void dumpParamList(int fd, paramList* l, uint64 ind, symtab* st);

/** @brief Function definition
 */
typedef struct {
    symcode id;
    paramList* pl;
    /// Body
    parserExp* b;
} functionDef;

/** @brief Constructor for function def
 */
functionDef* createFunctionDef();

/** @brief Destructor for function def
 */
void destroyFunctionDef(functionDef* f);

/** @brief Dumps info about the source
 */
void dumpFunctionDef(int fd, functionDef* f, uint64 ind, symtab* st);

/** @brief Independent source fragment
 */
typedef struct {
    /// # imports
    size_t nimp;
    /// Imports
    importStmt** imp;
    /// Number of function definitions
    size_t nf;
    /// Function definitions
    functionDef** f;
    /// Body
    parserExp* b;
} sourceFrag;

/** @brief Constructor for source fragment
 */
sourceFrag* createSourceFrag();

/** @brief Destructor for source fragment
 */
void destroySourceFrag(sourceFrag* sf);

/** @brief Push function def
 */
void sfPushFDef(sourceFrag* sf, functionDef* f);

void sfPushImport(sourceFrag* sf, importStmt* f);

/** @brief Dumps info about the source
 */
void dumpSourceFrag(int fd, sourceFrag* sf, uint64 ind, symtab* st);

#ifdef __cplusplus
}//extern "C"
#endif

#endif
